package com.xiaoniu66.webmagic.tianyancha.util;

import com.xiaoniu66.webmagic.tianyancha.bean.ProxyBean;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.SocketConfig;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Highly Concurrent Request Util
 * Created by hxy on 2018/3/20.
 */
public class HCRequestUtil {

    public static final HCRequestUtil ME = new HCRequestUtil();

    private final static PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager();

    private final static int socketTimeOutSeconds = 6; //socket读数据超时时间：从服务器获取响应数据的超时时间
    private final static int soLingerSeconds = 6; //关闭Socket时，要么发送完所有数据，要么等待soLingerSeconds后，就关闭连接，此时socket.close()是阻塞的
    private final static int maxTotal = 300;  //设置连接池的最大连接数
    private final static int defaultMaxPerRoute = 256;  //路由的默认最大连接

    private final static int connectTimeoutSeconds = 6; //与服务器连接超时时间：httpclient会创建一个异步线程用以创建socket连接，此处设置该socket的连接超时时间
    private final static int connectionRequestTimeoutSeconds = 6; //从连接池中获取连接的超时时间
    private final static int connectionTimeToLiveSeconds = 6;  //为持久链接设置的最大生存时间


    private HCRequestUtil() {
    }


    static {
        httpClientConnectionManager.setMaxTotal(maxTotal);
        httpClientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
        final int socketTimeout = socketTimeOutSeconds * 1000;
        SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(socketTimeout).setSoKeepAlive(false).setSoLinger(soLingerSeconds).build();
        httpClientConnectionManager.setDefaultSocketConfig(socketConfig);
    }

    /**
     * post 请求，使用时切记要关闭 HttpResponse
     *
     * @param url       url
     * @param headers   headers
     * @param params    params
     * @param proxyBean proxyBean
     * @return HttpResponse
     */
    public HttpResponse POST(String url, Map<String, String> headers, Map<String, String> params, ProxyBean proxyBean) {
        try {
            RequestConfig.Builder builder = RequestConfig.custom();
            builder.setSocketTimeout(socketTimeOutSeconds * 1000)
                    .setConnectTimeout(connectTimeoutSeconds * 1000)
                    .setConnectionRequestTimeout(connectionRequestTimeoutSeconds * 1000);
            if (proxyBean != null) {
                HttpHost httpHost = new HttpHost(proxyBean.getIp(), proxyBean.getPort());
                builder.setProxy(httpHost);
            }

            RequestConfig defaultRequestConfig = builder.build();
            HttpClientBuilder httpClientBuilder = HttpClients.custom()
                    .setConnectionManager(httpClientConnectionManager)
                    .setDefaultRequestConfig(defaultRequestConfig)
                    .setConnectionTimeToLive(connectionTimeToLiveSeconds * 1000, TimeUnit.MILLISECONDS)
                    .disableAutomaticRetries();  //禁止自动重试

            if (proxyBean != null && proxyBean.getUsername() != null) {
                CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                credentialsProvider.setCredentials(
                        AuthScope.ANY,
                        new UsernamePasswordCredentials(proxyBean.getUsername(), proxyBean.getUsername()));
                httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            }

            HttpPost httpPost = new HttpPost(url);
            if (headers != null && !headers.isEmpty()) {
                for (String key : headers.keySet()) {
                    String value = headers.get(key);
                    httpPost.addHeader(key, value);
                }
            }
            if (params != null && !params.isEmpty()) {
                List<NameValuePair> nameValuePairs = new ArrayList<>();
                for (String key : params.keySet()) {
                    String value = params.get(key);
                    nameValuePairs.add(new BasicNameValuePair(key, value));
                }
                httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
            }
            return httpClientBuilder.build().execute(httpPost);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * post 请求，使用时切记要关闭 HttpResponse
     *
     * @param url       url
     * @param headers   headers
     * @param proxyBean proxyBean
     * @return HttpResponse
     */
    public HttpResponse GET(String url, Map<String, String> headers, ProxyBean proxyBean) {
        try {
            RequestConfig.Builder builder = RequestConfig.custom();
            builder.setSocketTimeout(socketTimeOutSeconds * 1000)
                    .setConnectTimeout(connectTimeoutSeconds * 1000)
                    .setConnectionRequestTimeout(connectionRequestTimeoutSeconds * 1000);
            if (proxyBean != null) {
                HttpHost httpHost = new HttpHost(proxyBean.getIp(), proxyBean.getPort());
                builder.setProxy(httpHost);
            }

            RequestConfig defaultRequestConfig = builder.build();
            HttpClientBuilder httpClientBuilder = HttpClients.custom()
                    .setConnectionManager(httpClientConnectionManager)
                    .setDefaultRequestConfig(defaultRequestConfig)
                    .setConnectionTimeToLive(connectionTimeToLiveSeconds * 1000, TimeUnit.MILLISECONDS)
                    .disableAutomaticRetries();

            if (proxyBean != null && proxyBean.getUsername() != null) {
                CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                credentialsProvider.setCredentials(
                        AuthScope.ANY,
                        new UsernamePasswordCredentials(proxyBean.getUsername(), proxyBean.getUsername()));
                httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            }

            HttpGet httpGet = new HttpGet(url);
            for (String key : headers.keySet()) {
                String value = headers.get(key);
                httpGet.addHeader(key, value);
            }
            return httpClientBuilder.build().execute(httpGet);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


}
